/////////////////////////////////////////////////////////////////////////////////////
// Header Protection
#ifndef _VECTOR_H_
#define _VECTOR_H_

/////////////////////////////////////////////////////////////////////////////////////
// Include Files
#include <xmmintrin.h>

/////////////////////////////////////////////////////////////////////////////////////
// Type Definitions
typedef __m128 vector_t;

/////////////////////////////////////////////////////////////////////////////////////
// vector_t Declarations

inline vector_t Vector()
{
	return _mm_setzero_ps();
}

inline vector_t Vector( float_t _fX, float_t _fY, float_t _fZ, float_t _fW )
{
	return _mm_set_ps(_fW, _fZ, _fY,_fX );
}

inline vector_t Vector( float_t _fV )
{
	return _mm_set1_ps(_fV);
}

inline vector_t VectorSetX( vector_t _vYZW, float _fX )
{
	// TODO: is there any better way to do this, or which one of these is better?

	// uses few operations, but lots of change between vector and float*, incurs 2 LHS?
	// copy the vector, cast it as a float array, and set the x value
	// if this changed an internal vector, it would be faster
	vector_t vRet = _vYZW;
	((float*)&vRet)[0] = _fX;
	return vRet;

	//// uses more operations, but mostly in vector registers, only one LHS?
	//// create a vector from the x value, use it to create a new vector
	//vector_t vXXXX = _mm_set1_ps(_fX);
	//vector_t vXXYY = _mm_shuffle_ps(vXXXX, _vYZW, _MM_SHUFFLE(1, 1, 0, 0));
	//return _mm_shuffle_ps(vXXYY, _vYZW, _MM_SHUFFLE(3, 2, 2, 0));
}

inline vector_t VectorSetY( vector_t _vXZW, float_t _fY )
{
	// copy the vector, cast it as a float array, and set the y value
	vector_t vRet = _vXZW;
	((float*)&vRet)[1] = _fY;
	return vRet;

	//// create a vector from the y value, use it to create a new vector
	//vector_t vYYYY = _mm_set1_ps(_fY);
	//vector_t vXXYY = _mm_shuffle_ps(_vXZW, vYYYY, _MM_SHUFFLE(0, 0, 0, 0));
	//return _mm_shuffle_ps(vXXYY, _vXZW, _MM_SHUFFLE(3, 2, 2, 0));
}

inline vector_t VectorSetZ( vector_t _vXYW, float_t _fZ )
{
	// copy the vector, cast it as a float array, and set the z value
	vector_t vRet = _vXYW;
	((float*)&vRet)[2] = _fZ;
	return vRet;

	//// create a vector from the z value, use it to create a new vector
	//vector_t vZZZZ = _mm_set1_ps(_fZ);
	//vector_t vZZWW = _mm_shuffle_ps(vZZZZ, _vXYW, _MM_SHUFFLE(3, 3, 0, 0));
	//return _mm_shuffle_ps(_vXYW, vZZWW, _MM_SHUFFLE(2, 0, 1, 0));
}

inline vector_t VectorSetW( vector_t _vXYZ, float_t _fW )
{
	// copy the vector, cast it as a float array, and set the w value
	vector_t vRet = _vXYZ;
	((float*)&vRet)[3] = _fW;
	return vRet;

	//// create a vector from the w value, use it to create a new vector
	//vector_t vWWWW = _mm_set1_ps(_fW);
	//vector_t vZZWW = _mm_shuffle_ps(_vXYZ, vWWWW, _MM_SHUFFLE(0, 0, 2, 2));
	//return _mm_shuffle_ps(_vXYZ, vZZWW, _MM_SHUFFLE(2, 0, 1, 0));
}

inline vector_t Vector( float_t const *_pfV )
{
	return _mm_load_ps(_pfV);
}

inline vector_t VectorAdd( vector_t _lhs, vector_t _rhs )
{
	return _mm_add_ps(_lhs, _rhs);
}

inline vector_t VectorSub( vector_t _lhs, vector_t _rhs )
{
	return _mm_sub_ps(_lhs, _rhs);
}

inline vector_t VectorMul( vector_t _lhs, vector_t _rhs )
{
	return _mm_mul_ps(_lhs, _rhs);
}

inline vector_t VectorDiv( vector_t _lhs, vector_t _rhs )
{
	return _mm_div_ps(_lhs, _rhs);
}

// TODO: this may not need to reverse, check it out, also, move this somewhere
#define VEC_SHUFFLE_MASK(a, b, c, d) _MM_SHUFFLE(d, c, b, a)

template< int iMask >
inline vector_t VectorShuffle( vector_t _lhs, vector_t _rhs )
{
	return _mm_shuffle_ps(_lhs, _rhs, iMask);
}

vector_t VectorDot( vector_t _lhs, vector_t _rhs );

vector_t VectorCross( vector_t _lhs, vector_t _rhs );

vector_t VectorNorm( vector_t _lhs );

/////////////////////////////////////////////////////////////////////////////////////
// Header Protection
#endif // _VECTOR_H_
